package logger

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"go-gateworker/internal/config"

	"github.com/sirupsen/logrus"
)

// Logger 日志记录器
type Logger struct {
	*logrus.Logger
	cfg       *config.Config
	mu        sync.Mutex
	requestID string
}

var (
	// 全局日志实例
	globalLogger *Logger
	once         sync.Once
)

// Init 初始化全局日志
func Init(cfg *config.Config) {
	once.Do(func() {
		globalLogger = NewLogger(cfg)
	})
}

// GetLogger 获取全局日志实例
func GetLogger() *Logger {
	if globalLogger == nil {
		// 如果未初始化，使用默认配置初始化
		globalLogger = NewLogger(config.DefaultConfig())
	}
	return globalLogger
}

// NewLogger 创建新的日志记录器
func NewLogger(cfg *config.Config) *Logger {
	logger := logrus.New()

	// 设置日志级别
	level, err := logrus.ParseLevel(cfg.Logging.Level)
	if err != nil {
		level = logrus.InfoLevel
	}
	logger.SetLevel(level)

	// 设置日志格式
	if strings.ToLower(cfg.Logging.Format) == "json" {
		logger.SetFormatter(&logrus.JSONFormatter{
			TimestampFormat: cfg.Logging.TimeFormat,
		})
	} else {
		logger.SetFormatter(&logrus.TextFormatter{
			FullTimestamp:   true,
			TimestampFormat: cfg.Logging.TimeFormat,
		})
	}

	// 设置输出
	if strings.ToLower(cfg.Logging.Output) == "file" && cfg.Logging.FilePath != "" {
		// 确保日志目录存在
		logDir := filepath.Dir(cfg.Logging.FilePath)
		if err := os.MkdirAll(logDir, 0755); err != nil {
			fmt.Printf("创建日志目录失败: %v，将使用标准输出\n", err)
		} else {
			file, err := os.OpenFile(cfg.Logging.FilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
			if err != nil {
				fmt.Printf("打开日志文件失败: %v，将使用标准输出\n", err)
			} else {
				logger.SetOutput(file)
			}
		}
	}

	return &Logger{
		Logger: logger,
		cfg:    cfg,
	}
}

// UpdateConfig 更新日志配置
func (l *Logger) UpdateConfig(cfg *config.Config) {
	l.mu.Lock()
	defer l.mu.Unlock()

	l.cfg = cfg

	// 更新日志级别
	level, err := logrus.ParseLevel(cfg.Logging.Level)
	if err == nil {
		l.SetLevel(level)
	}

	// 更新日志格式
	if strings.ToLower(cfg.Logging.Format) == "json" {
		l.SetFormatter(&logrus.JSONFormatter{
			TimestampFormat: cfg.Logging.TimeFormat,
		})
	} else {
		l.SetFormatter(&logrus.TextFormatter{
			FullTimestamp:   true,
			TimestampFormat: cfg.Logging.TimeFormat,
		})
	}

	// 更新输出
	if strings.ToLower(cfg.Logging.Output) == "file" && cfg.Logging.FilePath != "" {
		// 确保日志目录存在
		logDir := filepath.Dir(cfg.Logging.FilePath)
		if err := os.MkdirAll(logDir, 0755); err != nil {
			l.Errorf("创建日志目录失败: %v", err)
			return
		}

		file, err := os.OpenFile(cfg.Logging.FilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
		if err != nil {
			l.Errorf("打开日志文件失败: %v", err)
			return
		}

		// 获取当前的输出对象，如果是文件就关闭它
		if w, ok := l.Out.(*os.File); ok && w != os.Stdout && w != os.Stderr {
			w.Close()
		}

		l.SetOutput(file)
	} else {
		// 获取当前的输出对象，如果是文件就关闭它
		if w, ok := l.Out.(*os.File); ok && w != os.Stdout && w != os.Stderr {
			w.Close()
		}
		l.SetOutput(os.Stdout)
	}
}

// SetOutput 设置输出目标
func (l *Logger) SetOutput(out io.Writer) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.Logger.SetOutput(out)
}

// WithRequestID 设置请求ID
func (l *Logger) WithRequestID(requestID string) *Logger {
	return &Logger{
		Logger:    l.Logger.WithField("request_id", requestID).Logger,
		cfg:       l.cfg,
		requestID: requestID,
	}
}

// WithFields 添加字段
func (l *Logger) WithFields(fields map[string]interface{}) *Logger {
	logrusFields := logrus.Fields{}
	for k, v := range fields {
		logrusFields[k] = v
	}

	if l.requestID != "" {
		logrusFields["request_id"] = l.requestID
	}

	return &Logger{
		Logger:    l.Logger.WithFields(logrusFields).Logger,
		cfg:       l.cfg,
		requestID: l.requestID,
	}
}

// NewEntry 创建新的日志条目
func (l *Logger) NewEntry() *logrus.Entry {
	if l.requestID != "" {
		return l.Logger.WithField("request_id", l.requestID)
	}
	return logrus.NewEntry(l.Logger)
}

// RequestLogger 请求日志中间件
func RequestLogger(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()

		// 生成请求ID
		requestID := generateRequestID()
		w.Header().Set("X-Request-ID", requestID)

		// 创建请求上下文的日志记录器
		log := GetLogger().WithRequestID(requestID).WithFields(map[string]interface{}{
			"method": r.Method,
			"path":   r.URL.Path,
			"remote": r.RemoteAddr,
		})

		log.Infof("开始处理请求")

		// 包装响应写入器以捕获状态码
		ww := NewResponseWriter(w)

		// 处理请求
		next.ServeHTTP(ww, r)

		// 记录请求处理结果
		duration := time.Since(start)
		statusCode := ww.Status()

		log = log.WithFields(map[string]interface{}{
			"status":      statusCode,
			"duration_ms": duration.Milliseconds(),
		})

		if statusCode >= 400 {
			log.Warnf("请求完成")
		} else {
			log.Infof("请求完成")
		}
	})
}

// ResponseWriter 响应写入器包装
type ResponseWriter struct {
	http.ResponseWriter
	status int
	size   int
}

// NewResponseWriter 创建新的响应写入器
func NewResponseWriter(w http.ResponseWriter) *ResponseWriter {
	return &ResponseWriter{
		ResponseWriter: w,
		status:         http.StatusOK,
	}
}

// WriteHeader 写入状态码
func (r *ResponseWriter) WriteHeader(status int) {
	r.status = status
	r.ResponseWriter.WriteHeader(status)
}

// Write 写入响应体
func (r *ResponseWriter) Write(b []byte) (int, error) {
	size, err := r.ResponseWriter.Write(b)
	r.size += size
	return size, err
}

// Status 获取状态码
func (r *ResponseWriter) Status() int {
	return r.status
}

// Size 获取响应大小
func (r *ResponseWriter) Size() int {
	return r.size
}

// 生成请求ID
func generateRequestID() string {
	now := time.Now()
	return fmt.Sprintf("%d%d", now.UnixNano(), time.Now().Unix()%1000)
}
